﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RestSharp;
using RestSharp.Authenticators;
using RestSharp.Contrib;
using FitbitAPI.Models;
using System.Net;
using System.IO;

namespace FitbitAPI
{
    public class Authenticator
    {
        private const string baseApiUrl = "https://api.fitbit.com";

        private string ConsumerKey;
        private string ConsumerSecret;
        private string RequestTokenUrl;
        private string AccessTokenUrl;
        private string AuthorizeUrl; 

        public Authenticator(string ConsumerKey, string ConsumerSecret, string RequestTokenUrl, string AccessTokenUrl, string AuthorizeUrl)
        {
            this.ConsumerKey = ConsumerKey;
            this.ConsumerSecret = ConsumerSecret;
            this.RequestTokenUrl = RequestTokenUrl;
            this.AccessTokenUrl = AccessTokenUrl;
            this.AuthorizeUrl = AuthorizeUrl;
        }

        /// <summary>
        /// Use this method first to retrieve a new OAuth_Token.
        /// Once they are done there, call to GetAuthVerifier.
        /// </summary>
        /// <returns></returns>
        public string GetAuthToken()
        {
            var baseUrl = baseApiUrl;
            var client = new RestClient(baseUrl);
            client.Authenticator = OAuth1Authenticator.ForRequestToken(this.ConsumerKey, this.ConsumerSecret);

            var request = new RestRequest("oauth/request_token", Method.POST);
            var response = client.Execute(request);

            if (response.StatusCode != System.Net.HttpStatusCode.OK)
                throw new Exception("Request Token Step Failed");

            var qs = HttpUtility.ParseQueryString(response.Content);
            var oauth_token = qs["oauth_token"];

            return oauth_token;
        }

        /// <summary>
        /// Use this method to validate a user and retrieve a the OAuth_Verifier.
        /// Once they are done there, call to GetAuthVerifier.
        /// </summary>
        /// <returns></returns>
        public string GetAuthVerifier(string Username, string Password, string OAuth_Token)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AuthorizeUrl + "?oauth_token=" + OAuth_Token);
            request.Method = "POST";

            //Data to Post to the Page, itis key value pairs; separated by "&"
            string data = "email=" + Uri.EscapeDataString(Username);
            data += "&password=" + Uri.EscapeDataString(Password);
            data += "&oauth_login_allow=on";
            data += "&oauth_token=" + Uri.EscapeDataString(OAuth_Token);

            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            //Getting the request stream and writing the post data
            using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
            {
                sw.Write(data);
            }

            HttpWebResponse firstResponse = (HttpWebResponse)request.GetResponse();

            string oauth_verifier = null;
            try
            {
                oauth_verifier = firstResponse.Headers.Get(firstResponse.Headers.AllKeys.First(x => x == "oauth_verifier"));
            }
            catch
            {
            }

            request.Abort();

            return oauth_verifier;
        }

        /// <summary>
        /// Use this method first to retrieve the url to redirect the user to to allow the url.
        /// Once they are done there, Fitbit will redirect them back to the predetermined completion URL
        /// </summary>
        /// <returns></returns>
        public string GetAuthUrlToken()
        {
            var baseUrl = baseApiUrl;
			var client = new RestClient(baseUrl);
			client.Authenticator = OAuth1Authenticator.ForRequestToken(this.ConsumerKey, this.ConsumerSecret);
            
            var request = new RestRequest("oauth/request_token", Method.POST);
			var response = client.Execute(request);

            if(response.StatusCode != System.Net.HttpStatusCode.OK)
                throw new Exception("Request Token Step Failed");

			var qs = HttpUtility.ParseQueryString(response.Content);
			var oauth_token = qs["oauth_token"];
			var oauth_token_secret = qs["oauth_token_secret"];

			request = new RestRequest("oauth/authorize");
			request.AddParameter("oauth_token", oauth_token);
			var url = client.BuildUri(request).ToString();

            return url;
        }

        public AuthCredential ProcessApprovedAuthCallback(string TempAuthToken, string Verifier)
        {
            var baseUrl = baseApiUrl;
            var client = new RestClient(baseUrl);
            client.Authenticator = OAuth1Authenticator.ForRequestToken(this.ConsumerKey, this.ConsumerSecret);

            var request = new RestRequest("oauth/access_token", Method.POST);

            client.Authenticator = OAuth1Authenticator.ForAccessToken(
                this.ConsumerKey, this.ConsumerSecret, TempAuthToken, "123456", Verifier
            );
            
            var response = client.Execute(request);

            var qs = HttpUtility.ParseQueryString(response.Content); //not actually parsing querystring, but body is formatted like htat
            var oauth_token = qs["oauth_token"];
            var oauth_token_secret = qs["oauth_token_secret"];
            var encoded_user_id = qs["encoded_user_id"];

            return new AuthCredential()
            {
                AuthToken = oauth_token,
                AuthTokenSecret = oauth_token_secret,
                UserId = encoded_user_id
            };
        }


    }
}
